package com.kmxd.ams.app.archive;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.ImmutableMap;
import com.kmxd.ams.client.archive.IArchiveClassifySvc;
import com.kmxd.ams.client.archive.IArchiveVersionSvc;
import com.kmxd.ams.client.archive.dto.ArchiveClassifyAddDTO;
import com.kmxd.ams.client.archive.dto.ArchiveClassifyEditDTO;
import com.kmxd.ams.client.archive.dto.ArchiveClassifyQueryDTO;
import com.kmxd.ams.client.archive.dto.ArchiveVersionQueryDTO;
import com.kmxd.ams.client.archive.vo.ArchiveClassifyListVO;
import com.kmxd.ams.client.archive.vo.ArchiveClassifyVO;
import com.kmxd.ams.client.archive.vo.ArchiveVersionListVO;
import com.kmxd.ams.client.arrange.dto.BaseQueryDTO;
import com.kmxd.ams.core.common.constant.Constants;
import com.kmxd.ams.core.common.constant.ErrorCode;
import com.kmxd.ams.core.common.query.QueryGen;
import com.kmxd.ams.core.exception.BizTipException;
import com.kmxd.ams.core.util.ConvertUtil;
import com.kmxd.ams.core.util.IdUtil;
import com.kmxd.ams.core.util.SecurityUtil;
import com.kmxd.ams.infra.archive.entity.ArchiveClassify;
import com.kmxd.ams.infra.archive.entity.ArchiveVersion;
import com.kmxd.ams.infra.archive.mapper.ArchiveClassifyMapper;
import java.util.*;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

/**
 * 整理规则-分类管理 服务实现类
 *
 * @author nickbi
 * @since 2022-07-19
 */
@Service
@Slf4j
@AllArgsConstructor
public class ArchiveClassifySvcImpl extends ServiceImpl<ArchiveClassifyMapper, ArchiveClassify>
    implements IArchiveClassifySvc {

  private ArchiveClassifyMapper archiveClassifyMapper;
  private IArchiveVersionSvc archiveVersionSvc;

  @Override
  public Page<ArchiveClassifyListVO> selectPage(Page reqPage, ArchiveClassifyQueryDTO req) {
    LambdaQueryWrapper<ArchiveClassify> queryWrapper =
        QueryGen.init(new QueryWrapper<ArchiveClassify>(), req).lambda();
    Page<ArchiveClassify> page = archiveClassifyMapper.selectPage(reqPage, queryWrapper);
    Page<ArchiveClassifyListVO> voPage = BeanUtil.copyProperties(page, Page.class);
    voPage.setRecords(BeanUtil.copyToList(page.getRecords(), ArchiveClassifyListVO.class));
    return voPage;
  }

  @Override
  public List<ArchiveClassifyListVO> selectList(ArchiveClassifyQueryDTO req) {
    LambdaQueryWrapper<ArchiveClassify> queryWrapper =
        QueryGen.init(new QueryWrapper<ArchiveClassify>(), req).lambda();
    List<ArchiveClassify> list = archiveClassifyMapper.selectList(queryWrapper);
    return BeanUtil.copyToList(list, ArchiveClassifyListVO.class);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void add(ArchiveClassifyAddDTO req) {
    req.setFondsId(
        ObjectUtil.isNotEmpty(req.getFondsId()) ? req.getFondsId() : SecurityUtil.getFondsId());
    ArchiveClassify entity = BeanUtil.copyProperties(req, ArchiveClassify.class);
    archiveClassifyMapper.insert(entity);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void edit(ArchiveClassifyEditDTO req) {
    ArchiveClassify entity = BeanUtil.copyProperties(req, ArchiveClassify.class);
    archiveClassifyMapper.updateById(entity);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void remove(String ids) {
    Set<Long> idList = IdUtil.split(ids);
    this.baseMapper.deleteBatchIds(idList);
  }

  @Override
  public ArchiveClassifyVO view(Long id) {
    ArchiveClassify entity = archiveClassifyMapper.selectById(id);
    return BeanUtil.copyProperties(entity, ArchiveClassifyVO.class);
  }

  @Override
  public List<Tree<String>> listClassifyTree(BaseQueryDTO req) {

    try {
      ArchiveVersion version = getVersion(req.getArchTypeId(), req.getYear());
      LambdaQueryWrapper<ArchiveClassify> queryWrapper = Wrappers.lambdaQuery();
      queryWrapper.eq(ArchiveClassify::getArchiveTypeId, req.getArchTypeId());
      queryWrapper.orderByAsc(ArchiveClassify::getSort);
      queryWrapper.eq(ArchiveClassify::getVersionId, version.getId());
      List<ArchiveClassify> classifyList = archiveClassifyMapper.selectList(queryWrapper);
      List treeNodeList =
          classifyList.stream()
              .map(
                  item -> {
                    TreeNode treeNode = new TreeNode();
                    treeNode.setId(item.getId().toString());
                    // todo...后期可以添加分类名称条件，防止分类号拼接产生二义性
                    treeNode.setExtra(
                        ImmutableMap.of(
                            "dataCondition",
                            item.getCode(),
                            "code",
                            item.getCode(),
                            "pigeonhole",
                            StrUtil.isNotBlank(item.getPigeonhole()) ? item.getPigeonhole() : "",
                            "deadline",
                            StrUtil.isNotBlank(item.getDeadline()) ? item.getDeadline() : "",
                            "secret",
                            StrUtil.isNotBlank(item.getSecret()) ? item.getSecret() : ""));
                    treeNode.setName(String.format("[%s]%s", item.getCode(), item.getName()));
                    treeNode.setParentId(item.getPid().toString());
                    treeNode.setWeight(item.getSort());
                    return treeNode;
                  })
              .collect(Collectors.toList());

      if (BooleanUtil.isTrue(req.getTree())) {
        TreeNode treeNode = new TreeNode();
        treeNode.setId("-1");
        treeNode.setExtra(ImmutableMap.of("dataCondition", ""));
        treeNode.setName("全部");
        treeNode.setParentId("0");
        treeNode.setWeight(-1);
        treeNodeList.add(treeNode);
      }
      List<Tree<String>> treeList = TreeUtil.build(treeNodeList, "0");

      String spliceCode = getSpliceCode(version);
      treeList.forEach(
          tree ->
              tree.walk(
                  node -> {
                    String parentId = node.getParentId();
                    // 顶级节点，不做拼接处理
                    if (parentId.equals(Constants.DEFAULT_TOP_TREE_PID)) {
                      return;
                    }
                    // 子节点进行拼接处理
                    Tree<String> parent = node.getParent();
                    Object parentCode = parent.get("code");
                    Object code = node.get("code");
                    String newCode = parentCode + spliceCode + code;
                    node.putExtra("dataCondition", newCode);
                    node.putExtra("code", newCode);
                    if (ObjectUtil.isNotEmpty(code) && ObjectUtil.isNotEmpty(node.getName())) {
                      String name = StrUtil.toString(node.getName());
                      String newName =
                          StrUtil.replace(name, name.indexOf("[") + 1, name.indexOf("]"), newCode);
                      node.putExtra("name", newName);
                    }
                  }));
      return CollectionUtils.isEmpty(treeList) ? new ArrayList() : treeList;
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      log.debug("获取分类树异常!:{}", e.getMessage());
    }
    return Lists.newArrayList();
  }

  /**
   * 拼接分类号
   *
   * @param version 分类版本
   * @return
   */
  private String getSpliceCode(ArchiveVersion version) {
    if (Objects.isNull(version)) {
      return "";
    }
    return Optional.ofNullable(version.getSplicer()).orElse("");
  }

  /**
   * 获取分类对应的版本信息
   *
   * @param archTypeId
   * @param year
   * @return
   */
  private ArchiveVersion getVersion(Long archTypeId, Integer year) {
    ArchiveVersionQueryDTO qry = new ArchiveVersionQueryDTO();
    qry.setArchiveTypeId(archTypeId);
    List<ArchiveVersionListVO> versionList = archiveVersionSvc.selectList(qry);
    if (ObjectUtil.isEmpty(versionList)) {
      throw BizTipException.instance(ErrorCode.ARCHIVE_VERSION_NOT_FOUND, "未找到版本信息");
    }
    final Integer finalYear = Objects.isNull(year) ? Constants.DEF_VERSION : year;
    long count = versionList.stream().filter(item -> Objects.isNull(item.getCode())).count();
    if (versionList.size() == count) {
      return ConvertUtil.toBean(versionList.get(0), ArchiveVersion.class);
    }
    Optional<ArchiveVersionListVO> max =
        versionList.stream()
            .filter(item -> finalYear >= Integer.parseInt(item.getCode()))
            .max(Comparator.comparing(item -> Integer.parseInt(item.getCode())));
    if (!max.isPresent()) {
      throw BizTipException.instance(ErrorCode.ARCHIVE_VERSION_NOT_FOUND, "未找到版本信息");
    }
    return ConvertUtil.toBean(max.get(), ArchiveVersion.class);
  }

  @Override
  public List<Tree<String>> tree(ArchiveClassifyQueryDTO req) {
    List<ArchiveClassifyListVO> list = selectList(req);
    List treeNodeList =
        list.stream()
            .map(
                item -> {
                  TreeNode<String> treeNode = new TreeNode();
                  treeNode.setId(item.getId().toString());
                  treeNode.setName(item.getName());
                  treeNode.setParentId(item.getPid().toString());
                  treeNode.setWeight(item.getSort());
                  Map<String, Object> map = BeanUtil.beanToMap(item);
                  Map<String, Object> stringMap =
                      map.entrySet().stream()
                          .collect(
                              Collectors.toMap(
                                  Map.Entry::getKey,
                                  e ->
                                      Objects.isNull(e.getValue())
                                          ? ""
                                          : String.valueOf(e.getValue())));
                  treeNode.setExtra(stringMap);
                  return treeNode;
                })
            .collect(Collectors.toList());
    List<Tree<String>> treeList =
        TreeUtil.build(treeNodeList, Optional.ofNullable(req.getPid()).orElse(0L).toString());
    return CollectionUtils.isEmpty(treeList) ? new ArrayList() : treeList;
  }

  @Override
  public ArchiveClassifyVO getAutoIndex(ArchiveClassifyEditDTO req) {
    LambdaQueryWrapper<ArchiveClassify> queryWrapper = Wrappers.lambdaQuery();
    queryWrapper.eq(ArchiveClassify::getArchiveTypeId, req.getArchiveTypeId());
    queryWrapper.orderByDesc(ArchiveClassify::getSort);
    queryWrapper.last("limit 1");
    ArchiveClassify one = this.getOne(queryWrapper);
    if (ObjectUtil.isEmpty(one)) {
      one = new ArchiveClassify();
    }
    one.setSort((ObjectUtil.isEmpty(one.getSort()) ? 1 : one.getSort()) + 1);
    return BeanUtil.copyProperties(one, ArchiveClassifyVO.class);
  }
}
